package com.coolw.core.optional;

import lombok.Data;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * Optional类是java8引入进来的，Optional是一个容器，它可以保存类型为T的值
 * <p>
 * Optional主要用来解决NullPointerException,Optional可以替代用if-else来解决空指针问题，使代码更简洁
 *
 * @author coolw
 * @date 2023/12/7 12:42
 */
public class OptionalTest {

    //------------------------------------ 常用方法 ------------------------------------
    // empty:返回一个空的Optional对象
    // of:将指定值用 Optional 封装之后返回，如果该值为 null，则抛出一个 NullPointerException 异常
    // ofNullable:将指定值用 Optional 封装之后返回，如果该值为 null，则返回一个空的 Optional 对象

    // get:如果该值存在，将该值用 Optional 封装返回，否则抛出一个 NoSuchElementException 异常
    // orElse:如果有值则将其返回，否则返回一个默认值
    // orElseGet:如果有值则将其返回，否则返回一个由指定的 Supplier 接口生成的值; (懒加载：只有当值不存在时才会去执行)
    // orElseThrow:如果有值则将其返回，否则抛出一个由指定的 Supplier 接口生成的异常; (懒加载：只有当值不存在时才会去执行)

    // ifPresent:如果值存在，就执行使用该值的方法调用，否则什么也不做
    // isPresent:如果值存在就返回 true，否则返回 false
    // map:如果值存在，就对该值执行提供的Function函数调用
    // flatMap:如果值存在，就对该值执行提供的Function函数调用，返回一个 Optional 类型的值，否则就返回一个空的 Optional 对象
    // filter:如果值存在并且满足提供的谓词，就返回包含该值的 Optional 对象;否则返回一个空的 Optional 对象

    //------------------------------------ Optional提供的一些基础类型的类 ------------------------------------
    // OptionalInt、OptionalLong、OptionalDouble：不支持Optional类中的map、flatMap、filter 方法，不推荐使用
    // 可以使用 Optional<Int>， Optional<Long>， Optional<Double> 来替代

    @Test
    public void test() {
        User user = new User();

        // 1.empty()：创建一个空的Optional对象
        Optional<Object> opt = Optional.empty();

        // 2.of(T value)：创建一个包含非空值的Optional对象,如果value为空，则报NullPointerException异常
        Optional<String> optStr = Optional.of("coolw");

        // 3.ofNullable(T value)：创建一个包含值（可为空）的Optional对象，如果值为空，则返回一个空的Optional对象
        Optional<User> optUser = Optional.ofNullable(user);

        // 4.get()：如果值存在，则返回该值；反之报NoSuchElementException异常
        String str = optStr.get();

        // 5.orElse(T other)：如果Optional包含的值不存在，则返回默认值other
        int age = optUser.map(User::getAge).orElse(18);

        // 6.orElseGet(Supplier<? extends T> other)：如果有值则将其返回，否则返回一个由指定的 Supplier 接口生成的值
        String address = optUser.map(User::getAddress).orElseGet(() -> "湖南省岳阳市");

        // 7.orElseThrow(Supplier<? extends X> exceptionSupplier)：如果有值则将其返回，否则抛出一个由指定的 Supplier 接口生成的异常
        String mobile = optUser.map(User::getMobile).orElseThrow(() -> new RuntimeException("手机号为空"));

        // 8.ifPresent(Consumer<? super T> consumer)：如果值存在，就执行使用该值的方法调用，否则什么也不做
        optUser.ifPresent(u -> u.setAge(20));

        // 9.isPresent()：如果值存在，返回true，否则返回false
        boolean present = optStr.isPresent();

        // 10.map(Function<? super T, ? extends U> mapper)：如果值存在，就对该值执行提供的Function函数调用;如果值不存在，则返回一个空的Optional对象
        Optional<String> optMobile = Optional.ofNullable(user).map(User::getMobile);

        // 11.flatMap(Function<? super T, Optional<U>> mapper)：多层嵌套的Optional结构，使用flatMap可以将多层的Optional对象合成一个
        List<String> list = Arrays.asList("a", "b", "c");
        Stream<char[]> flatMap = list.stream()
                .flatMap(s -> Stream.of(s.toCharArray()));

        // 12.filter(Predicate<? super T> predicate)：如果值存在并且满足条件，则返回满足条件的值；否则返回一个空的Optional对象
        optUser.filter(u -> user.getAge() > 18).ifPresent(x -> System.out.println(x.getUserName()));
    }

    @Data
    public static class User {

        private String userName;

        private String mobile;

        private Integer age;

        private String address;
    }
}
